package proxy

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/http/httputil"
	"net/url"
	"time"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"

	"yanxue_ai_go/pkg/common/logger"
	"yanxue_ai_go/services/gateway/internal/service"
)

// ServiceProxy 服务代理
type ServiceProxy struct {
	registry *service.ServiceRegistry
	clients  map[string]*http.Client
}

// NewServiceProxy 创建服务代理
func NewServiceProxy(registry *service.ServiceRegistry) *ServiceProxy {
	return &ServiceProxy{
		registry: registry,
		clients:  make(map[string]*http.Client),
	}
}

// getHTTPClient 获取HTTP客户端
func (sp *ServiceProxy) getHTTPClient(serviceName string) *http.Client {
	if client, exists := sp.clients[serviceName]; exists {
		return client
	}

	client := &http.Client{
		Timeout: 30 * time.Second,
		Transport: &http.Transport{
			MaxIdleConns:        100,
			MaxIdleConnsPerHost: 10,
			IdleConnTimeout:     30 * time.Second,
		},
	}

	sp.clients[serviceName] = client
	return client
}

// ProxyRequest 代理请求到指定服务
func (sp *ServiceProxy) ProxyRequest(c *gin.Context, serviceName string) {
	serviceInfo, exists := sp.registry.GetService(serviceName)
	if !exists {
		c.JSON(http.StatusServiceUnavailable, gin.H{
			"error": fmt.Sprintf("Service %s not available", serviceName),
		})
		return
	}

	if serviceInfo.Health != "healthy" {
		c.JSON(http.StatusServiceUnavailable, gin.H{
			"error": fmt.Sprintf("Service %s is unhealthy", serviceName),
		})
		return
	}

	// 构建目标URL
	targetURL := fmt.Sprintf("http://%s:%d", serviceInfo.Address, serviceInfo.Port)
	target, err := url.Parse(targetURL)
	if err != nil {
		logger.Logger.Error("Failed to parse target URL",
			zap.String("service", serviceName),
			zap.String("url", targetURL),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal server error"})
		return
	}

	// 创建反向代理
	proxy := httputil.NewSingleHostReverseProxy(target)

	// 自定义错误处理
	proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
		logger.Logger.Error("Proxy error",
			zap.String("service", serviceName),
			zap.String("path", r.URL.Path),
			zap.Error(err))

		w.WriteHeader(http.StatusBadGateway)
		w.Write([]byte(`{"error":"Bad Gateway"}`))
	}

	// 修改请求
	proxy.ModifyResponse = func(resp *http.Response) error {
		// 添加服务标识头
		resp.Header.Set("X-Service-Name", serviceName)
		resp.Header.Set("X-Gateway", "yanxue-gateway")
		return nil
	}

	// 记录请求日志
	startTime := time.Now()
	proxy.ServeHTTP(c.Writer, c.Request)
	duration := time.Since(startTime)

	logger.Logger.Info("Request proxied",
		zap.String("service", serviceName),
		zap.String("method", c.Request.Method),
		zap.String("path", c.Request.URL.Path),
		zap.Duration("duration", duration))
}

// ForwardRequestWithBody 转发请求并处理请求体
func (sp *ServiceProxy) ForwardRequestWithBody(c *gin.Context, serviceName, path string) {
	serviceInfo, exists := sp.registry.GetService(serviceName)
	if !exists {
		c.JSON(http.StatusServiceUnavailable, gin.H{
			"error": fmt.Sprintf("Service %s not available", serviceName),
		})
		return
	}

	// 读取请求体
	var bodyBytes []byte
	if c.Request.Body != nil {
		bodyBytes, _ = io.ReadAll(c.Request.Body)
		c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
	}

	// 构建目标URL
	targetURL := fmt.Sprintf("http://%s:%d%s", serviceInfo.Address, serviceInfo.Port, path)

	// 创建新请求
	req, err := http.NewRequestWithContext(c.Request.Context(), c.Request.Method, targetURL, bytes.NewBuffer(bodyBytes))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create request"})
		return
	}

	// 复制头部
	for key, values := range c.Request.Header {
		for _, value := range values {
			req.Header.Add(key, value)
		}
	}

	// 添加用户信息（从JWT中获取）
	if userID, exists := c.Get("user_id"); exists {
		req.Header.Set("X-User-ID", fmt.Sprintf("%v", userID))
	}
	if userRole, exists := c.Get("user_role"); exists {
		req.Header.Set("X-User-Role", fmt.Sprintf("%v", userRole))
	}

	// 发送请求
	client := sp.getHTTPClient(serviceName)
	startTime := time.Now()
	resp, err := client.Do(req)
	duration := time.Since(startTime)

	if err != nil {
		logger.Logger.Error("Failed to forward request",
			zap.String("service", serviceName),
			zap.String("path", path),
			zap.Error(err))
		c.JSON(http.StatusBadGateway, gin.H{"error": "Service unavailable"})
		return
	}
	defer resp.Body.Close()

	// 复制响应头
	for key, values := range resp.Header {
		for _, value := range values {
			c.Header(key, value)
		}
	}

	// 添加网关标识
	c.Header("X-Gateway", "yanxue-gateway")
	c.Header("X-Service-Name", serviceName)

	// 复制响应体
	c.Status(resp.StatusCode)
	io.Copy(c.Writer, resp.Body)

	// 记录日志
	logger.Logger.Info("Request forwarded",
		zap.String("service", serviceName),
		zap.String("method", c.Request.Method),
		zap.String("path", path),
		zap.Int("status", resp.StatusCode),
		zap.Duration("duration", duration))
}
